<?php
require_once(dirname(__FILE__) . "/../jdcr/php/nso/nusoap.php");
require_once(dirname(__FILE__) . "/../jdcr/php/dbu/PDOEx.inc.php");
require_once(dirname(__FILE__) . "/../jdcr/php/dcr/DefinedCrypt.php");
require_once(dirname(__FILE__) . "/../jdcr/php/gen/utilities.inc.php");
require_once(dirname(__FILE__) . "/../jdcr/php/cra/utilities.inc.php");
require(dirname(__FILE__) . "/php/config.inc.php");
require(dirname(__FILE__) . "/php/utilities.inc.php");
require(dirname(__FILE__) . "/php/BaseEmail.inc.php");

 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Definição do serviço
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

$server = new soap_server();
$server->soap_defencoding = "UTF-8";
$server->configureWSDL("zolm");

$server->register("getCryptographicKey"
                 ,array("aCpfCnpj" => "xsd:string"
                       ,"aSenha" => "xsd:string"
                       ,"aSoftwareId" => "xsd:integer")
                 ,array("return" => "xsd:string")
                 ,false
                 ,false
                 ,"rpc"
                 ,"encoded"
                 ,"Obtém a chave criptográfica do software de um determinado cliente"
);

$server->register("getPublicKey"
                 ,array("aCpfCnpj" => "xsd:string"
                       ,"aSenha" => "xsd:string")
                 ,array("return" => "xsd:string")
                 ,false
                 ,false
                 ,"rpc"
                 ,"encoded"
                 ,"Obtém a chave pública de um determinado cliente"
);

$server->register("validateHardware"
                 ,array("aCpfCnpj" => "xsd:string"
                       ,"aSenha" => "xsd:string"
                       ,"aSoftwareId" => "xsd:integer"
                       ,"aHardwareId" => "xsd:string")
                 ,array("return" => "xsd:integer")
                 ,false
                 ,false
                 ,"rpc"
                 ,"encoded"
                 ,"Verifica se um determinado software é habilidato para executar em um determinado hardware de um determinado cliente"
);

$server->register("registerHardware"
                 ,array("aCpfCnpj" => "xsd:string"
                       ,"aSenha" => "xsd:string"
                       ,"aSoftwareId" => "xsd:integer"
                       ,"aHardwareId" => "xsd:string"
                       ,"aOtherInformations" => "xsd:string")
                 ,array("return" => "xsd:integer")
                 ,false
                 ,false
                 ,"rpc"
                 ,"encoded"
                 ,"Registra um determinado software em um dado hardware de um determinado cliente"
);

$server->register("requestSerial"
                 ,array("aCpfCnpj" => "xsd:string"
                       ,"aSenha" => "xsd:string"
                       ,"aSoftwareId" => "xsd:integer"
                       ,"aHardwareId" => "xsd:string"
                       ,"aOtherInformations" => "xsd:string")
                 ,array("return" => "xsd:integer")
                 ,false
                 ,false
                 ,"rpc"
                 ,"encoded"
                 ,"Requisita um serial para um determinado software de um determinado cliente e envia este serial para o e-mail registrado do cliente"
);

$server->register("getNewVersion"
                 ,array("aSoftwareId" => "xsd:integer"
                       ,"aCurrentVersion" => "xsd:string"
                       ,"aCompareMode" => "xsd:string")
                 ,array("return" => "xsd:string")
                 ,false
                 ,false
                 ,"rpc"
                 ,"encoded"
                 ,"Retorna o endereço FTP do Instalador mais recente para o software indicado"
);

$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';

$server->service($HTTP_RAW_POST_DATA);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementação do serviço
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
* Obtém a chave de criptografia para um determinado software de um determinado cliente
* 
* Retorna
* > Uma chave criptográfica no formato "x;y;z|a;b;c"
* > "-1": Erro de operação PDO
* > "-2": Login mal sucedido
* > "-3": O cliente não possui licenças disponíveis para o software especificado
*/               
function getCryptographicKey($aCpfCnpj, $aSenha, $aSoftwareId) {
  $resultado = null;
  
  try {
    $zolm = new PDOEx(dbConfig()->getDsn(), dbConfig()->getUserName(), dbConfig()->getPassword());
    
    $sql = <<<EOS
select bi_clientes_id
  from CLIENTES
 where ch_cpfcnpj = '$aCpfCnpj'
   and lower(ch_senha) = lower('$aSenha')
EOS;
    
    $registros = $zolm->query($sql);
    $linha = $registros?$registros->fetchObject():false;

    // Caso o cliente exista usamos seu ID para saber se ele tem licenças para o software em questão
    if ($registros && $registros->rowCount() == 1) {
      $sql = <<<EOS
  select SDC.va_chavecriptografica
    from SISTEMASDOSCLIENTES SDC
   where SDC.bi_clientes_id = {$linha->bi_clientes_id}                             
     and SDC.bi_sistemas_id = $aSoftwareId
EOS;
      $registros = $zolm->query($sql);
      $linha = $registros?$registros->fetchObject():false;

      // Caso o cliente possua licenças para o software em questão, retornamos a chave criptogr?fica
      if ($registros && $registros->rowCount() == 1) {
        return $linha->va_chavecriptografica;
      } else {
        $resultado = -3;
      }

    } else {                 
      $resultado = -2;
    }
  } catch (PDOException $pdoException) {
    $resultado = -1;  
  }
  
  $zolm = null;
  return $resultado; 
}

/**
* Obtém a chave pública de um determinado cliente
* 
* Retorna
* > Uma chave pública de 128 Bytes
* > "-1": Erro de operação PDO
* > "-2": Login mal sucedido
*/               
function getPublicKey($aCpfCnpj, $aSenha) {
  
  $resultado = null;
  
  try {
    $zolm = new PDOEx(dbConfig()->getDsn(), dbConfig()->getUserName(), dbConfig()->getPassword(), TransactionIsolationLevel::tilSerializable);

    $sql = <<<EOS
select ch_chavepublica
  from CLIENTES
 where ch_cpfcnpj = '$aCpfCnpj'
   and lower(ch_senha) = lower('$aSenha')
EOS;
    
    $registros = $zolm->query($sql);
    $linha = $registros?$registros->fetchObject():false;
    
    if ($registros && $registros->rowCount() == 1) {
      return $linha->ch_chavepublica;
    } else {                 
      $resultado = -2;
    }
  } catch (PDOException $pdoException) {
    $resultado = -1;
  }
  $zolm = null;
  return $resultado; 
}

/**
* Valida um hardware para um software de um cliente
* 
* Retorna
* >  0: A licença existe para o hardware
* > -1: Erro de operação PDO
* > -2: Login mal sucedido
* > -3: O cliente não possui licenças disponíveis para o software especificado
* > -4: O hardware especificado não est? autorizado para o software em questão pertencente ao cliente
*/               
function validateHardware($aCpfCnpj, $aSenha, $aSoftwareId , $aHardwareId) {

  $resultado = null;
  
  try {
    $zolm = new PDOEx(dbConfig()->getDsn(), dbConfig()->getUserName(), dbConfig()->getPassword());
    
    $sql = <<<EOS
select bi_clientes_id
  from CLIENTES
 where ch_cpfcnpj = '$aCpfCnpj'
   and lower(ch_senha) = lower('$aSenha') 
EOS;
    
    $registros = $zolm->query($sql);
    $linha = $registros?$registros->fetchObject():false;

    // Caso o cliente exista usamos seu ID para saber se ele tem licenças para o software em questão
    if ($registros && $registros->rowCount() == 1) {
      $sql = <<<EOS
   select SDC.bi_sistemasdosclientes_id
        , count(LIC.bi_licencas_id) as licencas_ativas
     from SISTEMASDOSCLIENTES SDC
left join LICENCAS LIC using(bi_sistemasdosclientes_id)
    where SDC.bi_clientes_id = {$linha->bi_clientes_id}                             
      and SDC.bi_sistemas_id = $aSoftwareId
 group by SDC.bi_sistemasdosclientes_id
EOS;
      $registros = $zolm->query($sql);
      $linha = $registros?$registros->fetchObject():false;

      // Caso o cliente possua licenças ativas para o software em questão, precisamos saber se o hardware ? autorizado
      if ($registros && $registros->rowCount() == 1 && $linha->licencas_ativas > 0) {
        $sql = <<<EOS
select bi_licencas_id
  from LICENCAS
 where bi_sistemasdosclientes_id = {$linha->bi_sistemasdosclientes_id}
   and lower(ch_hardwareid) = lower('$aHardwareId')
EOS;
        $registros = $zolm->query($sql);
        $linha = $registros?$registros->fetchObject():false;

        if ($registros && $registros->rowCount() == 1) {
          $resultado = 0;
        } else {
          $resultado = -4;
        }
        
      } else {
        $resultado = -3;
      }

    } else {                 
      $resultado = -2;
    }
  } catch (PDOException $pdoException) {
    $resultado = -1;  
  }
  
  $zolm = null;
  return $resultado; 
}

/**
* Registra um hardware para um software de um cliente
* 
* Retorna
* >  0: Registro efetuado com sucesso
* > -1: Erro de operação PDO
* > -2: Login mal sucedido
* > -3: O cliente não possui licenças disponíveis para o software especificado
* > -4: não foi poss?vel confirmar o registro
*/               
function registerHardware($aCpfCnpj, $aSenha, $aSoftwareId , $aHardwareId, $aOtherInformations) {
  
  $resultado = null;
  
  try {
    $zolm = new PDOEx(dbConfig()->getDsn(), dbConfig()->getUserName(), dbConfig()->getPassword(), TransactionIsolationLevel::tilSerializable);
    $zolm->beginTransaction();

    $sql = <<<EOS
select bi_clientes_id
  from CLIENTES
 where ch_cpfcnpj = '$aCpfCnpj'
   and lower(ch_senha) = lower('$aSenha')
EOS;
    
    $registros = $zolm->query($sql);
    $linha = $registros?$registros->fetchObject():false;
    
    // Caso o cliente exista usamos seu ID para saber se ele tem licenças para o software em questão
    if ($registros && $registros->rowCount() == 1) {
      $sql = <<<EOS
   select SDC.bi_sistemasdosclientes_id
        , count(LIC.bi_licencas_id) as licencas_ativas
        , SDC.in_licencas as total_licencas
     from SISTEMASDOSCLIENTES SDC
left join LICENCAS LIC using(bi_sistemasdosclientes_id)
    where SDC.bi_clientes_id = {$linha->bi_clientes_id}                             
      and SDC.bi_sistemas_id = $aSoftwareId
 group by SDC.bi_sistemasdosclientes_id
        , SDC.in_licencas  
EOS;
      $registros = $zolm->query($sql);
      $linha = $registros?$registros->fetchObject():false;
                                                                                                                            
      // Caso o cliente possua licenças disponíveis para o software em questão, podemos registrar
      if ($registros && $registros->rowCount() == 1 && $linha->licencas_ativas < $linha->total_licencas) {
        $sql = <<<EOS
insert into LICENCAS (bi_sistemasdosclientes_id
                     ,ch_hardwareid
                     ,va_outrasinformacoes)
     values ({$linha->bi_sistemasdosclientes_id}
            ,'$aHardwareId'
            ,'$aOtherInformations') 
EOS;
        // Salva o ID do hardware para o software do cliente
        $registros = $zolm->query($sql);
        
        // Confiram as altera??es
        if ($registros && $zolm->commit()) {
          $resultado = 0;
        } else {
          $resultado = -4;
        }
        
      } else {
        $resultado = -3;
      }

    } else {                 
      $resultado = -2;
    }
  } catch (PDOException $pdoException) {
    $zolm->rollback();
    $resultado = -1;
  }
  $zolm = null;
  return $resultado; 
}

/**
* Solicita um serial válido para registro do software atual no hardware atual e envia para o e-mail registrado
* como detentor das licenças
* 
* Retorna
* >  0: Solicitação realizada com sucesso
* > -1: Erro de operação PDO
* > -2: Login mal sucedido
* > -3: O cliente não adquiriu o software em questão
* > -4: Resultado inválido (isso nunca deveria ocorrer)
* > -5: não existem mais licenças disponíveis 
* > -6: Não foi possível enviar o e-mail
*/               
function requestSerial($aCpfCnpj, $aSenha, $aSoftwareId, $aHardwareId, $aOtherInformations) {
  
  $resultado = null;
  
  try {
    $zolm = new PDOEx(dbConfig()->getDsn(), dbConfig()->getUserName(), dbConfig()->getPassword(), TransactionIsolationLevel::tilSerializable);

    $sql = <<<EOS
select bi_clientes_id
     , va_email
     , ch_chaveprivada
     , va_nome
  from CLIENTES
 where ch_cpfcnpj = '$aCpfCnpj'
   and lower(ch_senha) = lower('$aSenha')
EOS;
    
    $registros = $zolm->query($sql);
    $linha = $registros?$registros->fetchObject():false;
    
    if ($registros && $registros->rowCount() == 1) {
      $email = $linha->va_email;
      $chavePrivada = $linha->ch_chaveprivada; 
      $nomeCliente = $linha->va_nome;
      
      $sql = <<<EOS
   select SDC.in_licencas > count(LIC.bi_licencas_id) as registravel
        , SDC.va_chavecriptografica
        , SIS.va_nome
     from SISTEMASDOSCLIENTES SDC
     join SISTEMAS SIS using(bi_sistemas_id)
left join LICENCAS LIC using(bi_sistemasdosclientes_id)
    where SDC.bi_clientes_id = {$linha->bi_clientes_id}                             
      and SDC.bi_sistemas_id = $aSoftwareId
 group by SDC.va_chavecriptografica
        , SDC.in_licencas
        , SIS.va_nome
EOS;

      $registros = $zolm->query($sql);
      $linha = $registros?$registros->fetchObject():false;
      
      switch($registros->rowCount()) {
        case 0: 
          $resultado = -3; 
        break;
        case 1:
          if ($linha->registravel) {
            $chaveCriptografica = $linha->va_chavecriptografica;
            $nomeSistema = $linha->va_nome;

            $dc = new DefinedCrypt();
            $dc->setCryptTable(CryptTable::ctSafe);

            // Descriptgrafa o HardwareID
            $aHardwareId = $dc->privateKeyDecrypt($chavePrivada,$aHardwareId);
            
            // Aplica a parte A do hash no HardwareID
            $aHardwareId = getStringCheckSum($aHardwareId,ck2ha($chaveCriptografica,CryptographicSequence::csA),HashAlgorithms::haSha512);
            
            // Obtém a chave criptográfica completa
            $chaveCriptografica = getFullCk($chaveCriptografica);
            
            // Inicializa o template de e-mail
            $mailText = new BaseEmail("email.tpl");
            $mailText->assign("nomeCliente",$nomeCliente);
            $mailText->assign("nomeSistema",$nomeSistema);
            date_default_timezone_set("America/Recife");
            $mailText->assign("dataSolicitacao",date("d/m/Y à\s G:i:s"));
            $mailText->assign("chaveCriptografica",$chaveCriptografica);
            $mailText->assign("hardwareId",$aHardwareId);
            $mailText->assign("otherInformations",explode("<>",$aOtherInformations));

            if (sendMail(MAILFROM,$email,"Registro - " . $nomeSistema,$mailText->getContents())) {
              $resultado = 0;
            } else {
              $resultado = -6;  
            }
            
      // 4. no cliente o hash "A" é validado, se for o hash "A" for válido...
      // 5. ...envia o Hash "A" na função registerHardware 
          } else {
            $resultado = -5;  
          }
        break;
        default: // Mais de 1 resultado
          $resultado = -4;
      }
    } else {                 
      $resultado = -2;
    }
  } catch (PDOException $pdoException) {
    $resultado = -1;
  }
  
  $zolm = null;
  
  return $resultado; 
}
//echo(requestSerial("00000000000000", "e10adc3949ba59abbe56e057f20f883e", 1, "hardware id (isso influencia naquilo que é retornado por e-mail)", "informação adicional #1<>informação adicional #2<>informação adicional #n"));

/**
* Retorna o endereço FTP do instalador mais recente para o software indicado,
* juntamente com seu MD5
* 
* Parâmetros
* > $aSoftwareId: Identificação do software a verificar
* > $aCurrentVersion: Versão, no formato Ma.Mi.R.B a ser comparada com a versão no servidor
* > $aCompareMode: Modo de comparação. Indica como as versões serão comparadas. Veja a ajuda
*                  sobre o parâmetro "operator" da função "version_compare". $aCurrentVersion
*                  é passada como segundo parâmetro para a função "version_compare", logo,
*                  tenha isso em mente ao informar este parâmetro, de forma que a comparação
*                  de versões tenha o comportamento desejado
* 
* Retorna
* >  String com endereço FTP do instalador, e seu MD5, separado por um caractere ","
* >  0: Não há uma nova versão disponível 
* > -1: Erro de operação PDO
* > -2: Sistema inexistente (SoftwareID incorreto)
*/               
function getNewVersion($aSoftwareId, $aCurrentVersion, $aCompareMode) {
  //cria a classe ftpconfig e em config.inc.php configura um endereço de ftp e um nome genérico para o instaladors
    
  $resultado = null;
  
  try {
    $zolm = new PDOEx(dbConfig()->getDsn(), dbConfig()->getUserName(), dbConfig()->getPassword(), TransactionIsolationLevel::tilSerializable);

    $sql = <<<EOS
select va_urlinstalador
     , va_pathinstalador
  from SISTEMAS
 where bi_sistemas_id = $aSoftwareId
EOS;
    
    $registros = $zolm->query($sql);
    $linha = $registros?$registros->fetchObject():false;
    
    if ($registros && $registros->rowCount() == 1) {
      $versaoInstalador = GetWindowsExeInfo($linha->va_pathinstalador, 'ProductVersion');
      
      if (version_compare($versaoInstalador,$aCurrentVersion,$aCompareMode)) {
        $resultado = $linha->va_urlinstalador . "," . md5_file($linha->va_pathinstalador); 
      } else {
        $resultado = 0;
      }
    } else {                 
      $resultado = -2;
    }
  } catch (PDOException $pdoException) {
    $resultado = -1;
  }
  
  $zolm = null;
  
  return $resultado; 
}

//criar uma função que recebe como parâmetro o aSoftwareId e a versão do instalador que é sempre 
//a mesma versão do produto instalado, pois o que vai buscar do servidor, é sempre o mesmo para 
//todo cliente que usa o mesmo software
//isso é seguro, pois os softwares contém a sistema de licenciamento 
//a função deve retornar o caminho ftp completo caso haja uma versão nova do software
//o cliente baixa o instalador e fecha o programa, executando em seguida o instalador em modo 
//silencioso caso não consiga executar mantém ele na pasta
//se tentar baixar novamente, verifica se na pasta existe o instalador e só baixa se for uma 
//versão mais nova, excluindo o instalador anterior

?>